
$component_catalogue = {}

class Component
  attr_accessor :manufacturer, :name, :price, :weight, :slots, :uid
  attr_reader :owner
  attr_writer :description # reader is done manually
  
  def initialize
    #$components << self
    @weight = 0
  end
  
  def description
    return @description if @description
    return @manufacturer + " " + @name
  end
  
  def add_to(owner)
    @owner = owner
    @owner.components << self
    @owner.body.m += @weight
    @owner.recalculate_moment
  end
  
  def remove_from(owner)
    @owner.body.m -= @weight
    @owner.recalculate_moment
    @owner.components.delete(self)
    @owner = nil
  end
  
  def update
  end
  
end

class Engine < Component
  attr_accessor :move_force, :turn_force, :reverse_factor
  
  def initialize
    super
    @reverse_factor = 0.5
  end
  
  def accelerate
    @owner.push @move_force
  end
  
  def reverse
    @owner.push -@reverse_factor * @move_force
  end
  
  
end

class WheeledEngine < Engine
  def turn_left
    @owner.shape.body.t -= @turn_force/SUBSTEPS * @owner.body.v.length
  end
  
  def turn_right
    @owner.shape.body.t += @turn_force/SUBSTEPS * @owner.body.v.length
  end
end

class JetEngine < Engine
    
  def turn_left
    @owner.shape.body.t -= @turn_force/SUBSTEPS
  end
  
  def turn_right
    @owner.shape.body.t += @turn_force/SUBSTEPS
  end
end

class Weapon < Component
  attr_accessor :ammo # a new one of these is spawned on fire
  
  attr_accessor :chamber_time #time between shots
  attr_accessor :reload_time #time between clips #TODO
	attr_accessor :shots_per_fire
	attr_accessor :time_between_shots_per_fire
	
  attr_reader :shot_time_countdown, :shot_countdown
  attr_reader :chamber_countdown, :reload_countdown
  
  attr_accessor :override_angle
  
  attr_accessor :clip_size
  
  attr_accessor :weapon_group
  
  attr_accessor :recoil_force
  
  def initialize()
    super()
    @shot_class = nil
    
    @chamber_time = 0.25
    @chamber_countdown = 0
    @recoil_force = 0
    @shots_per_fire = 1
    @time_between_shots_per_fire = 0
    @shot_countdown = 0
    @shot_time_countdown = 0
  end
  
  def add_to(owner, group)
    super(owner)
    @weapon_group = group
  end
  
  def fire
    if @chamber_countdown > 0 then
      return
    end
    
    @chamber_countdown = @chamber_time
		
		@shot_countdown = @shots_per_fire
		
		fire_shot
    
  end
	
	def fire_shot
    if @override_angle == nil
      angle = @owner.aim_angle
    else
      angle = @override_angle
    end
		@ammo.new(@owner.body.p.x,@owner.body.p.y,angle,@owner)
    
    if @owner.respond_to? :push then
      if @owner.has_turret? then
        @owner.push_at_angle -(@recoil_force), @owner.aim_angle
      else
        @owner.push -(@recoil_force)
      end
    end
		
		@shot_time_countdown = @time_between_shots_per_fire if @shots_per_fire > 1
		
		@shot_countdown -= 1
		
		#puts "%i %i" % [@shot_countdown, @shot_time_countdown]
	end
		
  
  def update
    if @chamber_countdown > 0 then
      @chamber_countdown -= $dt
    end
		
		@shot_countdown -= $dt if @shot_countdown > 0
		@shot_time_countdown -= $dt if @shot_time_countdown > 0
		fire_shot if @shot_countdown > 0 and @shot_time_countdown <= 0
    
    
  end
  
  def percent_ready
    v = (1 - (@chamber_countdown / @chamber_time)) * 100
    v = 0 if v < 0
    v = 100 if v > 100
    
    v
  end
end

def initialize_components
  path = path_for './components'
	rbfiles = Dir.entries(path).select {|x| /\.yml\z/ =~ x}
	
  #rbfiles -= [ File.basename(__FILE__) ]
  
  rbfiles.each do |path|
    init_component_with_file(path_for('./components/'+path))
  end
  
  return ;

  e = WheeledEngine.new
  e.manufacturer = "ThrustCorp"
  e.name = "TC01"
  e.move_force = 300
  e.turn_force = 200
  e.weight = 3
  #$component_catalogue[WheeledEngine] << e
  
  e = JetEngine.new
  e.manufacturer = "ThrustCorp"
  e.name = "J-1000"
  e.move_force = 10
  e.turn_force = 200
  e.weight = 1
  #$component_catalogue[JetEngine] << e
  
  
  
  w = Weapon.new
  w.ammo = Bullet
  w.manufacturer = "SnuggleCorp"
  w.name = "Blaster Mk. 1"
  w.weight = 2
  w.chamber_time = 0.1
  #$component_catalogue[Weapon] << w
  
  w = Weapon.new
  w.manufacturer = "FlamingDeath"
  w.ammo = Rocket
  w.name = "Immolator R53"
  w.weight = 4
  w.chamber_time = 5
  w.recoil_force = 2000
  w.shots_per_fire = 5
  w.time_between_shots_per_fire = 0.1
  #$component_catalogue[Weapon] << w
  
  w = Weapon.new
  w.manufacturer = "Kill-O-Zap"
  w.ammo = LaserBolt
  w.name = "Scorchinator"
  w.weight = 2
  w.chamber_time = 0.5
  w.recoil_force = 0
  w.shots_per_fire = 1
  w.time_between_shots_per_fire = 0.1
  #$component_catalogue[Weapon] << w
  
  
end

def init_component_with_file(path)
	
	f = File.new(path)
	component_list = YAML.load(f)
	
	component_list.each do |desc|
		component_class = $spawnable_objects[desc['type']]
		c = component_class.new
    
    c.uid = (desc['uid'] or 'no-uid-this-is-bad')
    c.weight = (desc['weight'] or 0)
    puts 'foo'
    
    if c.is_a? Weapon then
      
      c.ammo = ($spawnable_objects[desc['ammo']] or Bullet)
      c.manufacturer = (desc['manufacturer'] or 'No Manufacturer')
      c.name = (desc['name'] or 'No Name')
      c.chamber_time = (desc['chamber_time'] or 1)
      c.recoil_force = (desc['recoil_force'] or 0)
      c.shots_per_fire = (desc['shots_per_fire'] or 1)
      c.time_between_shots_per_fire = (desc['time_between_shots_per_fire'] or 1)
    end
    
    if c.is_a? Engine then
      c.move_force = (desc['move_force'] or 300)
      c.turn_force = (desc['turn_force'] or 200)
    end
        
    $component_catalogue[c.uid] = c
    
	end
  
  f.close
	
end
